import { Slider as AntdSlider, Space } from 'antd';
import { useState, useEffect } from 'react';

import type { SliderRangeProps, SliderSingleProps } from 'antd/es/slider';

import { InputNumber } from '@/components/eai-design';
import { cn } from '@/utils/cn-merge';

import '../styles/slider.scss';

/**
 * 自定义滑块组件属性类型
 * 支持单值和范围两种模式
 */
type CustomSliderProps = (
  | (SliderSingleProps & { range?: undefined })
  | (SliderRangeProps & { range: true | SliderRangeProps['range'] })
) & {
  /** 滑块尺寸 */
  size?: 'small' | 'default';
  /** 是否显示数字输入框 */
  showInput?: boolean;
  /** 输入框的属性 */
};

/**
 * 自定义滑块组件
 *
 * 基于 Ant Design 的 Slider 组件封装，提供了自定义样式、尺寸选项和数字输入框功能。
 * 支持单值和范围两种模式，可以垂直或水平显示，并提供丰富的自定义选项。
 *
 * ## 功能特性
 * -  支持单值和范围两种模式
 * -  提供 small 和 default 两种尺寸
 * -  可选的数字输入框，支持精确输入
 * -  支持水平和垂直方向
 * -  自定义样式和主题
 * -  完整的 TypeScript 类型支持
 * -  受控和非受控模式
 *
 * ## 参数说明
 * @param size - 滑块尺寸，可选 'small' | 'default'，默认为 'default'
 *   - 'small': 小尺寸，适用于紧凑布局
 *   - 'default': 默认尺寸，适用于常规布局
 * @param showInput - 是否显示数字输入框，默认为 false
 *   - true: 显示输入框，用户可以直接输入数值
 *   - false: 仅显示滑块
 * @param className - 自定义 CSS 类名
 * @param range - 是否为范围滑块
 *   - true: 范围模式，返回 [min, max] 数组
 *   - false/undefined: 单值模式，返回单个数值
 * @param vertical - 是否为垂直滑块，默认为 false
 * @param min - 最小值，默认为 0
 * @param max - 最大值，默认为 100
 * @param step - 步长，默认为 1
 * @param value - 受控模式的值
 * @param defaultValue - 非受控模式的默认值
 * @param onChange - 值变化回调函数
 * @param disabled - 是否禁用
 * @param marks - 刻度标记对象
 * @param included - 是否包含关系，默认为 true
 * @param dots - 是否只能拖拽到刻度上，默认为 false
 * @param tooltip - 工具提示相关配置
 *
 * ## 使用示例
 *
 * ### 基础用法
 * ```tsx
 * // 简单滑块
 * <Slider defaultValue={30} />
 *
 * // 受控模式
 * const [value, setValue] = useState(50);
 * <Slider value={value} onChange={setValue} />
 * ```
 *
 * ### 尺寸变体
 * ```tsx
 * // 默认尺寸
 * <Slider defaultValue={50} />
 *
 * // 小尺寸滑块
 * <Slider size="small" defaultValue={50} />
 * ```
 *
 * ### 带数字输入框
 * ```tsx
 * // 单值模式 + 输入框
 * <Slider showInput defaultValue={50} min={0} max={100} />
 *
 * // 范围模式 + 输入框
 * <Slider showInput range defaultValue={[20, 80]} />
 * ```
 *
 * ### 范围滑块
 * ```tsx
 * // 基础范围滑块
 * <Slider range defaultValue={[20, 50]} />
 *
 * // 带步长的范围滑块
 * <Slider range defaultValue={[20, 50]} step={10} />
 *
 * // 受控范围滑块
 * const [range, setRange] = useState([20, 80]);
 * <Slider range value={range} onChange={setRange} />
 * ```
 *
 * ### 垂直滑块
 * ```tsx
 * // 垂直单值滑块
 * <Slider vertical defaultValue={30} style={{ height: 200 }} />
 *
 * // 垂直范围滑块
 * <Slider vertical range defaultValue={[20, 50]} style={{ height: 200 }} />
 *
 * // 垂直滑块 + 输入框
 * <Slider vertical showInput defaultValue={30} style={{ height: 200 }} />
 *
 * // 垂直范围滑块 + 输入框
 * <Slider vertical showInput range defaultValue={[20, 50]} style={{ height: 200 }} />
 * ```
 *
 * ### 带标记的滑块
 * ```tsx
 * // 温度滑块
 * <Slider
 *   marks={{
 *     0: '0°C',
 *     26: '26°C',
 *     37: '37°C',
 *     100: '100°C'
 *   }}
 *   defaultValue={37}
 *   step={null}
 * />
 *
 * // 评分滑块
 * <Slider
 *   marks={{
 *     1: '😞',
 *     2: '😐',
 *     3: '😊',
 *     4: '😍',
 *     5: '🤩'
 *   }}
 *   min={1}
 *   max={5}
 *   defaultValue={3}
 * />
 * ```
 *
 * ### 高级配置
 * ```tsx
 * // 禁用状态
 * <Slider disabled defaultValue={50} />
 *
 * // 自定义工具提示
 * <Slider
 *   tooltip={{
 *     formatter: (value) => `${value}%`,
 *     placement: 'top'
 *   }}
 *   defaultValue={50}
 * />
 *
 * // 只能拖拽到刻度点
 * <Slider
 *   marks={{ 0: '0', 25: '25', 50: '50', 75: '75', 100: '100' }}
 *   step={null}
 *   defaultValue={50}
 * />
 * ```
 *
 * ## 注意事项
 * - 在范围模式下，确保传入的 defaultValue 或 value 是数组格式 [min, max]
 * - 垂直滑块需要设置容器高度才能正常显示
 * - 使用 marks 时，建议设置 step={null} 以只允许选择标记点
 * - 垂直滑块支持输入框，输入框会显示在滑块下方
 * - 输入框会自动限制输入值在 min-max 范围内
 * - 范围滑块的输入框会自动保证第一个值不大于第二个值
 *
 * ## 样式定制
 * 组件使用了自定义的 SCSS 样式，可以通过以下 CSS 类名进行样式定制：
 * - `.rg-slider`: 基础滑块样式
 * - `.rg-slider--small`: 小尺寸样式
 * - `.rg-slider--default`: 默认尺寸样式
 * - `.rg-slider--vertical`: 垂直滑块样式
 * - `.rg-slider--vertical--small`: 垂直小尺寸样式
 * - `.rg-slider--vertical--default`: 垂直默认尺寸样式
 */
export const Slider = ({
  size = 'default',
  className,
  showInput = false,
  ...props
}: CustomSliderProps) => {
  // 垂直滑块使用专门的垂直样式类，水平滑块使用尺寸样式类
  const sizeClass = props.vertical ? `rg-slider--vertical--${size}` : `rg-slider--${size}`;

  // 状态管理
  const [internalValue, setInternalValue] = useState<number | number[]>(
    props.value ?? props.defaultValue ?? (props.range ? [0, 0] : 0),
  );

  // 同步外部value变化
  useEffect(() => {
    if (props.value !== undefined) {
      setInternalValue(props.value);
    }
  }, [props.value]);

  // 处理滑块值变化
  const handleSliderChange = (value: number | number[]) => {
    if (props.value === undefined) {
      setInternalValue(value);
    }
    // 根据range模式调用正确的onChange类型
    if (props.range) {
      (props.onChange as (value: number[]) => void)?.(value as number[]);
    } else {
      (props.onChange as (value: number) => void)?.(value as number);
    }
  };

  // 处理输入框值变化
  const handleInputChange = (value: number | null | undefined) => {
    if (value === null || value === undefined) return;

    const newValue = Math.max(props.min ?? 0, Math.min(props.max ?? 100, value));

    if (props.value === undefined) {
      setInternalValue(newValue);
    }
    (props.onChange as (value: number) => void)?.(newValue);
  };

  // 处理range模式下的输入框值变化
  const handleRangeInputChange = (value: number | null | undefined, index: 0 | 1) => {
    if (value === null || value === undefined) return;

    const newValue = Math.max(props.min ?? 0, Math.min(props.max ?? 100, value));
    const currentArray = Array.isArray(currentValue) ? [...currentValue] : [0, 0];
    currentArray[index] = newValue;

    // 确保第一个值不大于第二个值
    if (index === 0) {
      currentArray[1] = Math.max(currentArray[0], currentArray[1]);
    } else if (index === 1) {
      currentArray[0] = Math.min(currentArray[0], currentArray[1]);
    }

    if (props.value === undefined) {
      setInternalValue(currentArray);
    }
    // 只在range模式下调用onChange，确保类型匹配
    if (props.range) {
      (props.onChange as (value: number[]) => void)?.(currentArray);
    }
  };

  // 获取当前值
  const currentValue = props.value ?? internalValue;

  const getMarginTop = () => {
    if (size !== 'small') return -9;
    return -10; // props.marks 不影响结果，可统一返回 -10
  };

  // 如果不显示输入框，直接返回滑块
  if (!showInput) {
    return props.range ? (
      <AntdSlider
        {...(props as any)}
        range
        value={currentValue as number[]}
        onChange={handleSliderChange}
        className={cn(props.vertical ? 'rg-slider--vertical' : 'rg-slider', className, sizeClass)}
      />
    ) : (
      <AntdSlider
        {...(props as any)}
        value={currentValue as any}
        onChange={handleSliderChange}
        className={cn(props.vertical ? 'rg-slider--vertical' : 'rg-slider', className, sizeClass)}
      />
    );
  }

  // 带输入框的滑块（支持水平和垂直）
  const { style, ...restProps } = props;

  // 垂直滑块的布局样式
  const containerStyle = props.vertical
    ? { display: 'flex', flexDirection: 'column' as const, alignItems: 'center', gap: 12 }
    : { display: 'flex', alignItems: 'flex-start', gap: 12 };

  // 滑块的样式
  const sliderStyle = props.vertical
    ? { height: style?.height || 200, ...style }
    : { flex: 1, ...style };

  return (
    <Space.Compact style={containerStyle}>
      {props.range ? (
        <AntdSlider
          {...(restProps as any)}
          range
          value={currentValue as number[]}
          onChange={handleSliderChange}
          className={cn(props.vertical ? 'rg-slider--vertical' : 'rg-slider', className, sizeClass)}
          style={sliderStyle}
        />
      ) : (
        <AntdSlider
          {...(restProps as any)}
          value={currentValue as number}
          onChange={handleSliderChange}
          className={cn(props.vertical ? 'rg-slider--vertical' : 'rg-slider', className, sizeClass)}
          style={sliderStyle}
        />
      )}
      {props.range ? (
        <div
          className="align-center flex items-center gap-2"
          style={props.vertical ? {} : { marginTop: size === 'small' ? -10 : -9 }}
        >
          <InputNumber
            disabled={props.disabled}
            style={{ width: 68, height: 32 }}
            min={props.min}
            max={Array.isArray(currentValue) ? currentValue[1] : props.max}
            step={props.step as number | string}
            value={(Array.isArray(currentValue) ? currentValue[0] : 0) as any}
            onChange={(value) => handleRangeInputChange(value as number | null | undefined, 0)}
          />
          <div>-</div>
          <InputNumber
            disabled={props.disabled}
            style={{ width: 68, height: 32 }}
            min={Array.isArray(currentValue) ? currentValue[0] : props.min}
            max={props.max}
            step={props.step as number | string}
            value={(Array.isArray(currentValue) ? currentValue[1] : 0) as any}
            onChange={(value) => handleRangeInputChange(value as number | null | undefined, 1)}
          />
        </div>
      ) : (
        <InputNumber
          disabled={props.disabled}
          style={{
            width: 68,
            height: 32,
            marginTop: props.vertical ? 0 : getMarginTop(),
          }}
          min={props.min}
          max={props.max}
          step={props.step as number | string}
          value={currentValue as number}
          onChange={(value) => handleInputChange(value as number | null | undefined)}
        />
      )}
    </Space.Compact>
  );
};
